package com.gillion.grule.client.components;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.gillion.grule.client.core.Component;
import com.gillion.grule.client.core.Context;
import com.gillion.grule.client.core.ExecuteComponent;
import com.gillion.grule.client.core.SpringCloudConfig;
import com.gillion.grule.client.utils.ContextHolder;
import com.google.common.collect.Lists;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.mvel2.MVEL;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;

@Component("SpringCloudService")
public class SpringCloudComponent extends ExecuteComponent {
    private static final Logger LOGGER = LoggerFactory.getLogger(SpringCloudComponent.class);


    private static RestTemplate restTemplate;


    public <T> T execute(String express, Context context) {
        LOGGER.info("规则引擎 调用 springCloud 配置：" + express);
        JSONObject jSONObject = JSON.parseObject(express);
        String serverName = jSONObject.get("springCloudName").toString();
        List<String> expressParams = (List<String>)jSONObject.get("params");
        List<Object> params = Lists.newArrayList();
        List<SpringCloudConfig> list = context.getSpringCloudConfig();
        SpringCloudConfig config = new SpringCloudConfig();

        for (SpringCloudConfig springCloudConfig : list) {
            if (springCloudConfig.getSpringCloudName().equals(serverName)) {
                config = springCloudConfig;
            }
        }



        for (int i = 0; i < expressParams.size(); i++) {
            Object obj = expressParams.get(i);
            if (obj instanceof String) {
                try {
                    params.add(MVEL.eval(expressParams.get(i), context).toString());
                } catch (Exception e) {
                    params.add(MVEL.eval("'" + (String)expressParams.get(i) + "'", context).toString());
                }
            } else {
                params.add(expressParams.get(i));
            }
        }

        Map<String, Object> paramsMap = (Map<String, Object>)params.get(0);




        prepareRestTemplate();
        try {
            String url = config.getRequestMapping();
            String requestType = config.getRequestType();
            Class<?> resultClass = getClass(config.getRequestResult());
            LOGGER.info("SpringCloud服务调用开始，服务地址：" + url);
            ResponseEntity<?> response = executeHttpRequest(url, requestType, paramsMap, resultClass);
            LOGGER.info("SpringCloud服务调用结束，状态码：" + response.getStatusCode());
            return (T)response.getBody();
        } catch (Exception e) {
            throw new RuntimeException(String.format("springCloud服务请求异常,url:%s", new Object[] { config.getRequestMapping() }), e);
        }
    }

    private ResponseEntity<?> executeHttpRequest(String url, String type, Map<String, Object> paramMap, Class<?> resultClass) {
        switch (type) {
            case "get":
                return executeGet(url, paramMap, resultClass);
        }
        return executePost(url, paramMap, resultClass);
    }


    private void prepareRestTemplate() {
        if (restTemplate == null) {
            restTemplate = (RestTemplate) ContextHolder.getBean(RestTemplate.class);
        }
    }

    private ResponseEntity<?> executeGet(String url, Map<String, Object> paramMap, Class<?> resultClass) {
        String finalUrl = spliceUrlParams(url, paramMap);
        return restTemplate.exchange(finalUrl, HttpMethod.GET, null, resultClass, paramMap);
    }

    private ResponseEntity<?> executePost(String url, Map<String, Object> paramMap, Class<?> resultClass) {
        HttpHeaders headers = new HttpHeaders();
        headers.set("Content-Type", "application/json;charset=UTF-8");
        headers.setAcceptCharset(Lists.newArrayList(new Charset[] { StandardCharsets.UTF_8 }));
        HttpEntity<Map<String, Object>> httpEntity = new HttpEntity(paramMap, headers);
        return restTemplate.exchange(url, HttpMethod.POST, httpEntity, resultClass, new Object[0]);
    }

    private Class<?> getClass(String resultType) {
        try {
            return Class.forName(resultType);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException("返回类型解析异常", e);
        }
    }

    private static String spliceUrlParams(String url, Map<String, Object> paramMap) {
        StringBuilder stringBuffer = new StringBuilder(url);
        Iterator iterator = paramMap.entrySet().iterator();
        if (iterator.hasNext()) {
            stringBuffer.append("?");

            while (iterator.hasNext()) {
                Object element = iterator.next();
                Map.Entry<String, Object> entry = (Map.Entry<String, Object>)element;

                if (entry.getValue() != null) {
                    stringBuffer.append(element).append("&");
                }
                url = stringBuffer.substring(0, stringBuffer.length() - 1);
            }
        }
        return url;
    }
}